package com.boyinet.data.export.service;

import com.boyinet.data.export.domain.DataHistory;
import com.boyinet.data.export.repoistory.DataHistoryRepository;
import com.boyinet.data.export.vo.SearchParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author lengchunyun
 */
@Service
@Slf4j
public class ExportDataService {

    public static final int THREE_TEN_MINUTES = 10 * 60 * 1000;

    private static final int SIZE = 3000;
    private final DataHistoryRepository dataHistoryRepository;

    public ExportDataService(DataHistoryRepository dataHistoryRepository) {
        this.dataHistoryRepository = dataHistoryRepository;
    }

    public void export(OutputStream outputStream, SearchParam searchParam) throws IOException {
        /*XSSFWorkbook wb = new XSSFWorkbook();*/
        Workbook wb = new SXSSFWorkbook(1000);
        Sheet sheet = wb.createSheet();
        List<String> ids = searchParam.getIds();
        int size = ids.size();

        CellStyle centerCellStyle = setCellStyle(wb);

        CellStyle dateCellStyle = wb.createCellStyle();
        dateCellStyle.setDataFormat(wb.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));

        setHead(sheet, ids, size, centerCellStyle);
        int rowIndex = 2;

        // 获取数据的最大行数
        List<Long> counts = ids.stream().map(id -> dataHistoryRepository
                .countByEquipmentIdEqualsAndGmtCreateBetween(id, searchParam.getStartTime().getTime(),
                        searchParam.getEndTime().getTime())).collect(Collectors.toList());

        long max = counts.stream().max(Long::compare).orElse(0L);
        if (max == 0) {
            wb.close();
            return;
        }
        long page = max / SIZE + 1;

        Row valueRow = sheet.createRow(rowIndex);
        for (long i = 0; i < page; i++) {

            //分页获取数据
            int finalI = (int) i;
            Map<String, List<DataHistory>> map = ids.stream().collect(
                    Collectors.toMap(s -> s, s -> dataHistoryRepository
                            .pageDataHistoriesByEquipmentIdEqualsAndGmtCreateBetween(s, searchParam.getStartTime(),
                                    searchParam.getEndTime(), PageRequest.of(finalI, SIZE)).getContent()
                    ));

            //推进行的移动

            if (page == 1) {
                for (int j = 0; j < max; j++) {
                    writeCell(ids, size, valueRow, map, j, dateCellStyle);
                    valueRow = sheet.createRow(j + 3);
                }
            } else if (i <= page - 1) {
                for (int j = 0; j < SIZE; j++) {
                    //写当前行的值
                    writeCell(ids, size, valueRow, map, j, dateCellStyle);
                    valueRow = sheet.createRow((int) (i * SIZE + j + 3));
                }
            } else {
                for (int j = 0; j < max - ((page - 1) * SIZE); j++) {
                    writeCell(ids, size, valueRow, map, j, dateCellStyle);
                    valueRow = sheet.createRow((int) (i * SIZE + j + 3));
                }
            }
        }

        //合并头
        for (int i = 0; i < size; i++) {
            CellRangeAddress cell1 = new CellRangeAddress(0, 0, i * 2, i * 2 + 1);
            sheet.addMergedRegion(cell1);
        }
        wb.write(outputStream);
        outputStream.close();
        wb.close();
    }

    private void setHead(Sheet sheet, List<String> ids, int size, CellStyle centerCellStyle) {
        Row headRow = sheet.createRow(0);
        Row infoRow = sheet.createRow(1);
        for (int i = 0; i < size * 2; i++) {
            //1、设置头
            Cell headRowCell = headRow.createCell(i);
            headRowCell.setCellStyle(centerCellStyle);
            //2、设置数值
            Cell infoRowCell = infoRow.createCell(i);
            infoRowCell.setCellStyle(centerCellStyle);
            if (i % 2 == 0) {
                headRowCell.setCellValue(ids.get(i / 2));
                infoRowCell.setCellValue("创建时间");
                sheet.setColumnWidth(i, (int) (22 + 0.72) * 256);
            } else {
                infoRowCell.setCellValue("当前压力(Bar)");
                sheet.setColumnWidth(i, (int) (15 + 0.72) * 256);
            }
        }
    }

    private CellStyle setCellStyle(Workbook wb) {
        CellStyle centerCellStyle = wb.createCellStyle();
        centerCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        centerCellStyle.setAlignment(HorizontalAlignment.CENTER);
        centerCellStyle.setBorderLeft(BorderStyle.THIN);
        centerCellStyle.setBorderTop(BorderStyle.THIN);
        centerCellStyle.setBorderRight(BorderStyle.THIN);
        centerCellStyle.setBorderBottom(BorderStyle.THIN);
        return centerCellStyle;
    }

    private void writeCell(List<String> ids, int size, Row valueRow, Map<String, List<DataHistory>> map, int j, CellStyle cellStyle) {
        for (int i = 0; i < size; i++) {
            final Cell timeCell = valueRow.createCell(i * 2);
            final Cell valueCell = valueRow.createCell(i * 2 + 1);
            if (j < map.get(ids.get(i)).size()) {
                Optional.ofNullable(map.get(ids.get(i)).get(j)).ifPresent(d -> {
                    timeCell.setCellValue(new Date(d.getGmtCreate()));
                    timeCell.setCellStyle(cellStyle);
                    valueCell.setCellValue(Double.parseDouble(d.getDataValue()));
                });
            }
        }
    }

    public void exportByTime(HttpServletResponse response, SearchParam searchParam) throws IOException {

        Workbook wb = new SXSSFWorkbook(100);
        Sheet sheet = wb.createSheet();
        List<String> ids = searchParam.getIds();
        int size = ids.size();

        CellStyle centerCellStyle = setCellStyle(wb);

        CellStyle dateCellStyle = wb.createCellStyle();
        dateCellStyle.setDataFormat(wb.createDataFormat().getFormat("HH:mm:ss"));

        setHead(sheet, ids, size, centerCellStyle);
        int rowIndex = 2;

        long start = searchParam.getStartTime().getTime();
        long end = searchParam.getEndTime().getTime();

        long range = end - start;
        log.info("[数据导出] 时间区间为{}MS", range);

        List<Long> counts = ids.stream().map(id -> dataHistoryRepository
                .countByEquipmentIdEqualsAndGmtCreateBetween(id, start, end)).collect(Collectors.toList());

        long max = counts.stream().max(Long::compare).orElse(0L);
        if (max == 0) {
            log.info("[数据导出] 当前数据记录数为空");
            wb.close();
            return;
        }

        Row valueRow = sheet.createRow(rowIndex);
        if (range <= THREE_TEN_MINUTES) {
            Map<String, List<DataHistory>> map = ids.stream().collect(
                    Collectors.toMap(s -> s, s -> dataHistoryRepository
                            .findDataHistoriesByEquipmentIdEqualsAndGmtCreateBetween(s, start, end)));
            for (int j = 0; j < max; j++) {
                writeCell(ids, size, valueRow, map, j, dateCellStyle);
                valueRow = sheet.createRow(rowIndex++);
            }
        } else {
            long page = range / THREE_TEN_MINUTES + 1;
            for (long i = 0; i < page; i++) {
                long index = start + (i * THREE_TEN_MINUTES);
                counts = ids.stream().map(id -> dataHistoryRepository
                        .countByEquipmentIdEqualsAndGmtCreateBetween(id, index,
                                index + THREE_TEN_MINUTES)).collect(Collectors.toList());

                max = counts.stream().max(Long::compare).orElse(0L);
                if (max == 0) {
                    wb.close();
                    return;
                }
                Map<String, List<DataHistory>> map = ids.stream().collect(
                        Collectors.toMap(s -> s, s -> dataHistoryRepository
                                .findDataHistoriesByEquipmentIdEqualsAndGmtCreateBetween(s, index,
                                        index + THREE_TEN_MINUTES)
                        ));
                for (int j = 0; j < max; j++) {
                    writeCell(ids, size, valueRow, map, j, dateCellStyle);
                    valueRow = sheet.createRow(rowIndex++);
                }
            }
        }
        //合并头
        for (int i = 0; i < size; i++) {
            CellRangeAddress cell1 = new CellRangeAddress(0, 0, i * 2, i * 2 + 1);
            sheet.addMergedRegion(cell1);
        }

        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("History", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        ServletOutputStream out = response.getOutputStream();
        wb.write(out);
        out.close();
        wb.close();
    }
}
